package interpreter

import (
	"lambda"
	"regexp"
	"stdlib"
	"bridge/list"
	"bridge/module"
)

type Interpreter interface {
	Interpret(name string) lambda.Term
}

type FileReader interface {
	ReadFile(name string) []byte
}

type BuiltinParser interface {
	Parse(body []byte) module.Module
}

func New(reader FileReader) Interpreter {
	return interpreter{
		reader:        reader,
		env:           stdlib.ENV,
		defaultSyntax: "__BUILTIN__",
		builtin:       nil,
	}
}

var header = regexp.MustCompile("^[\n]*syntax[ ]+([^\n]*)\n(.*)$")

type interpreter struct {
	reader        FileReader
	env           lambda.Environment
	defaultSyntax string
	builtin       BuiltinParser
}

func (interp interpreter) Interpret(filename string) lambda.Term {
	file := interp.reader.ReadFile(filename)

	syntax, body := getSyntaxAndBody(file)

	if syntax == "" {
		syntax = interp.defaultSyntax
	}

	var mod module.Module
	if syntax == "__BUILTIN__" {
		mod = interp.builtin.Parse(body)
	} else {
		parser_term := interp.Interpret(syntax)
		module_term := lambda.App(parser_term, lambda.Prim(body))
		mod = module.FromTerm(module_term, interp.env)
	}

	deps := list.Empty()
	for i := len(mod.Deps) - 1; i >= 0; i-- {
		deps = list.PushFront(interp.Interpret(mod.Deps[i]), deps)
	}

	return lambda.App(mod.Body, deps)
}

func getSyntaxAndBody(file []byte) (syntax string, body []byte) {
	matches := header.FindSubmatch(file)

	if matches == nil || len(matches) != 3 {
		syntax, body = "", file
	} else {
		syntax, body = string(matches[1]), matches[2]
	}
	return
}
